package com.mjk.common.core.jdbc.service.plus.provider.abstractor;


import com.mjk.common.base.model.BaseEntity;
import com.mjk.common.core.jdbc.annotation.ArcSharding;
import com.mjk.common.core.jdbc.ibatis.typehandler.handler.*;
import com.mjk.common.core.jdbc.service.plus.constns.BeeTypeEntity;
import com.mjk.common.core.jdbc.service.plus.provider.BeeDataSourceType;
import com.mjk.common.core.jdbc.service.plus.provider.interfaces.IBeeProvider;
import com.mjk.common.core.jdbc.service.plus.provider.interfaces.IBeeTypeMapping;
import com.mjk.common.util.TimeUtils;
import org.apache.ibatis.type.JdbcType;

import java.math.BigDecimal;
import java.sql.Clob;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;


public abstract class AbstractMysqlProvider implements IBeeProvider, IBeeTypeMapping {

    private Set<BeeTypeEntity> allMapping = allMapping = new HashSet<>(Arrays.asList(
            new BeeTypeEntity(JdbcType.BIT, "BIT", Boolean.class.getName(), "4", 0, new BooleanHandler()),
            new BeeTypeEntity(JdbcType.TINYINT, "TINYINT", Byte.class.getName(), "4", 1, new ByteHandler()),
            new BeeTypeEntity(JdbcType.SMALLINT, "SMALLINT", Short.class.getName(), "4", 0, new ShortHandler()),
            new BeeTypeEntity(JdbcType.INTEGER, "INT", Integer.class.getName(), "11", 0, new IntegerHandler()),
            new BeeTypeEntity(JdbcType.BIGINT, "BIGINT", Long.class.getName(), "20", 1, new LongHandler()),
            new BeeTypeEntity(JdbcType.FLOAT, "FLOAT", Float.class.getName(), "1", 0, new FloatHandler()),
            new BeeTypeEntity(JdbcType.REAL, "FLOAT", Float.class.getName(), "0", 0, new FloatHandler()),
            new BeeTypeEntity(JdbcType.DOUBLE, "DOUBLE", Double.class.getName(), "10,2", 1, new DoubleHandler()),
            new BeeTypeEntity(JdbcType.DECIMAL, "DECIMAL", BigDecimal.class.getName(), "0", 0, new BigDecimalHandler()),
            new BeeTypeEntity(JdbcType.CHAR, "CHAR", String.class.getName(), "1", 0, new StringHandler()),
            new BeeTypeEntity(JdbcType.VARCHAR, "VARCHAR", String.class.getName(), "255", 1, new StringHandler()),
            new BeeTypeEntity(JdbcType.LONGVARCHAR, "LONGVARCHAR", Clob.class.getName(), "255", 0, new ClobHandler()),
            new BeeTypeEntity(JdbcType.DATE, "DATE", Date.class.getName(), "0", 0, new DateHandler()),
            new BeeTypeEntity(JdbcType.TIMESTAMP, "TIMESTAMP", Timestamp.class.getName(), "6", 0, new DateHandler()),
            new BeeTypeEntity(JdbcType.TIME, "TIME", java.sql.Time.class.getName(), "0", 0, new DateHandler()),
            new BeeTypeEntity(JdbcType.BINARY, "BINARY", Byte.class.getName(), "1", 0, new ByteHandler()),
            new BeeTypeEntity(JdbcType.TIMESTAMP, "TIMESTAMP", LocalDateTime.class.getName(), "6", 0, new LocalDateTimeHandler()),
            new BeeTypeEntity(JdbcType.DATE, "DATE", LocalDate.class.getName(), "0", 0, new LocalDateHandler()),
            new BeeTypeEntity(JdbcType.TIME, "TIME", LocalTime.class.getName(), "1", 0, new LocalTimeHandler()),
            new BeeTypeEntity(JdbcType.VARBINARY, "TINYBLOB", Byte.class.getName(), "4", 0, new ByteHandler()),
            new BeeTypeEntity(JdbcType.LONGVARBINARY, "BLOB", Byte.class.getName(), "4", 0, new ByteHandler()),
            new BeeTypeEntity(JdbcType.BLOB, "TEXT", java.sql.Blob.class.getName(), "0", 1, new BlobHandler()),
            new BeeTypeEntity(JdbcType.CLOB, "TEXT", java.sql.Clob.class.getName(), "0", 1, new ClobHandler()),
            new BeeTypeEntity(JdbcType.OTHER, "VARCHAR", String.class.getName(), "255", 0, new StringHandler())
    ));

    private Map<String, BeeTypeEntity> javaMapping;

    protected AbstractMysqlProvider() {
        javaMapping = initJavaTypeMap(allMapping);
    }

    @Override
    public Set<BeeTypeEntity> getMapping() {
        return allMapping;
    }

    @Override
    public Map<JdbcType, BeeTypeEntity> getJdbcMap() {
        return allMapping.stream().collect(Collectors.toMap(BeeTypeEntity::getJdbcType, obj -> obj, (key1, key2) -> key1));
    }

    @Override
    public Map<String, BeeTypeEntity> getJavaMap() {
        return javaMapping;
    }



    @Override
    public String getCreateTable(BaseEntity entiry) {
        return "CREATE TABLE %s ( " + buildFiledSql(entiry, BeeDataSourceType.MYSQL_WRAP) + " )ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;\r\n";
    }

    @Override
    public String getTableStruct(String tabName) {
        return "select * from " + tabName + " LIMIT 0";
    }

    @Override
    public String getTableStructDetail(ArcSharding arc) {
         String sql = "select table_name,COLUMN_NAME,DATA_TYPE,COLUMN_COMMENT from information_schema.COLUMNS " ;
         if (arc.table() != null) {
             sql = sql + " where table_name = '" + arc.table() + "';";
         }
         return sql;
    }

    @Override
    public String getAutoIncrement(boolean primary) {
        if(primary){
            return " primary key auto_increment";
        }
        return "";
    }

    @Override
    public String getTabName(ArcSharding arc) {
        return arc.table();
    }



    @Override
    public String getAlertAdd(boolean isUpdate) {
        return " ,";
    }
    @Override
    public String getComment(String comment) {
        if (comment.isEmpty()) {
            return "";
        }else {
            return " COMMENT '" + comment + "'";
        }
    }

    @Override
    public String getAlertDrop(List<String> fieldNames) {
        StringBuilder sb = new StringBuilder();
        for(String fieldName : fieldNames){
            sb.append(" drop column ").append(fieldName).append(",");
        }
        return sb.toString();
    }

    @Override
    public String trancationField(Object o,String condition) {
        if(o instanceof Date){
            SimpleDateFormat sdf = new SimpleDateFormat(TimeUtils.DATE_FORMAT_DATETIME);
            return  sdf.format(TimeUtils.parse(o.toString()));
        }
        return null;
    }
}
